// DeflaterOutputBuffer.cs
//
// Copyright (C) 2001 Mike Krueger
// Copyright (C) 2004 John Reilly
// Copyright (C) 2010 Thomas Maierhofer
//
// (2010) This Code was modified from SharpZipLib http://www.icsharpcode.net/OpenSource/SharpZipLib/  
// to fit the needs of Second WAF - a heavy load web application framework 
//
// This file was translated from java, it was part of the GNU Classpath
// Copyright (C) 2001 Free Software Foundation, Inc.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//
// Linking this library statically or dynamically with other modules is
// making a combined work based on this library.  Thus, the terms and
// conditions of the GNU General Public License cover the whole
// combination.
// 
// As a special exception, the copyright holders of this library give you
// permission to link this library with independent modules to produce an
// executable, regardless of the license terms of these independent
// modules, and to copy and distribute the resulting executable under
// terms of your choice, provided that you also meet, for each linked
// independent module, the terms and conditions of the license of that
// module.  An independent module is a module which is not derived from
// or based on this library.  If you modify this library, you may extend
// this exception to your version of the library, but you are not
// obligated to do so.  If you do not wish to do so, delete this
// exception statement from your version.



namespace WAF.Content
{
    using System;
    using System.Diagnostics;

    public partial class Deflater
	{
        /*
        public void InitOutputBuffer(int bufferSize, Deflater.StoreDataDelegate storeData, object context)
		{
            this.StoreData = storeData;
            this.storeDataContext = context;
            this.outputBufferSize = bufferSize;
            outputBuffer = new byte[this.outputBufferSize];
		}
        */
        /*
        internal void OutputBufferReset()
        {
            outputBufferStart = 0;
            outputBufferEnd = 0;
            outputBufferBitCount = 0;
        }
        */
        /// <summary>
		/// Write a short value to buffer LSB first
		/// </summary>
		/// <param name="value">
		/// The value to write.
		/// </param>
        internal void OutputBufferWriteShortLSBFirst(uint value)
		{
            Debug.Assert(outputBufferStart == 0);
			outputBuffer[outputBufferEnd++] = unchecked((byte) value);
            if (outputBufferEnd >= outputBufferSize) SendBuffer();
			outputBuffer[outputBufferEnd++] = unchecked((byte) (value >> 8));
            if (outputBufferEnd >= outputBufferSize) SendBuffer();
        }

        internal void OutputBufferWriteShort(uint value)
        {
            Debug.Assert(outputBufferStart == 0);
            outputBuffer[outputBufferEnd++] = unchecked((byte)(value >> 8));
            if (outputBufferEnd >= outputBufferSize) SendBuffer(); 
            outputBuffer[outputBufferEnd++] = unchecked((byte)value);
            if (outputBufferEnd >= outputBufferSize) SendBuffer();

        }
		
		/// <summary>
		/// Write a block of data to buffer
		/// </summary>
		/// <param name="block">data to write</param>
		/// <param name="offset">offset of first byte to write</param>
		/// <param name="length">number of bytes to write</param>
        internal void OutputBufferWriteBlock(byte[] block, int offset, int length)
		{
            throw new NotSupportedException();
            /*
            Debug.Assert(outputBufferStart == 0);
            // Buffer.BlockCopy ?
			System.Array.Copy(block, offset, outputBuffer, outputBufferEnd, length);
			outputBufferEnd += length;
             */
		}

		
		/// <summary>
		/// Align internal buffer on a byte boundary
		/// </summary>
        internal void OutputBufferAlignToByte() 
		{
            Debug.Assert(outputBufferStart == 0);
			if (outputBufferBitCount > 0) 
			{
                if (outputBufferEnd + 6 >= outputBufferSize) SendBuffer();

				outputBuffer[outputBufferEnd++] = unchecked((byte) outputBufferBits);

				while(outputBufferBitCount > 8) 
                {
                    outputBufferBits >>= 8;
                    outputBuffer[outputBufferEnd++] = unchecked((byte)outputBufferBits);
                    outputBufferBitCount -= 8;
				}
			}
			outputBufferBits = 0;
			outputBufferBitCount = 0;
		}

        /// <summary>
        /// Writes Bits to to the output buffer
        /// </summary>
        /// <param name="bits">The bit values</param>
        /// <param name="count">The bit count</param>
        /// <remarks>RFC 1951 (3.1.1) defines the byte order as less significant bit first.
        /// </remarks>
        internal void OutputBufferWriteSymbol(HuffmanTree.Symbol symbol)
        {
            Debug.Assert(outputBufferStart == 0);
            outputBufferBits |= ((ulong)(symbol.BitsCode)) << outputBufferBitCount;
            outputBufferBitCount += symbol.Bits;

            if (outputBufferBitCount >= 48)
            {
                if (outputBufferEnd + 6 >= outputBufferSize) SendBuffer();


                outputBuffer[outputBufferEnd++] = unchecked((byte)outputBufferBits);
                outputBufferBits >>= 8;
                outputBuffer[outputBufferEnd++] = unchecked((byte)outputBufferBits);
                outputBufferBits >>= 8;
                outputBuffer[outputBufferEnd++] = unchecked((byte)outputBufferBits);
                outputBufferBits >>= 8;
                outputBuffer[outputBufferEnd++] = unchecked((byte)outputBufferBits);
                outputBufferBits >>= 8;
                outputBuffer[outputBufferEnd++] = unchecked((byte)outputBufferBits);
                outputBufferBits >>= 8;
                outputBuffer[outputBufferEnd++] = unchecked((byte)outputBufferBits);
                outputBufferBits >>= 8;
                outputBufferBitCount -= 48;


                /*
                outputBuffer[outputBufferEnd] = unchecked ((byte) outputBufferBits);
                outputBuffer[outputBufferEnd+1] = unchecked ((byte) (outputBufferBits >> 8));
                outputBuffer[outputBufferEnd+2] = unchecked((byte)(outputBufferBits >> 16));
                outputBuffer[outputBufferEnd+3] = unchecked((byte)(outputBufferBits >> 24));
                outputBuffer[outputBufferEnd+4] = unchecked((byte)(outputBufferBits >> 32));
                outputBuffer[outputBufferEnd+5] = unchecked((byte)(outputBufferBits >> 40));
                outputBufferEnd += 6;
                outputBufferBits >>= 48;
                outputBufferBitCount -= 48;
                */
            }
        }

        /// <summary>
        /// Writes Bits to to the output buffer
        /// </summary>
        /// <param name="bits">The bit values</param>
        /// <param name="count">The bit count</param>
        /// <remarks>RFC 1951 (3.1.1) defines the byte order as less significant bit first.
        /// </remarks>
        internal void OutputBufferWriteSymbol(HuffmanTree.Symbol[] symbols, int count)
        {
            for (int index = 0; index < count; ++index)
            {
                HuffmanTree.Symbol symbol = symbols[index];
                Debug.Assert(outputBufferStart == 0);
                outputBufferBits |= ((ulong)(symbol.BitsCode)) << outputBufferBitCount;
                outputBufferBitCount += symbol.Bits;

                if (outputBufferBitCount >= 48)
                {
                    if (outputBufferEnd + 6 >= outputBufferSize) SendBuffer();


                    outputBuffer[outputBufferEnd++] = unchecked((byte)outputBufferBits);
                    outputBufferBits >>= 8;
                    outputBuffer[outputBufferEnd++] = unchecked((byte)outputBufferBits);
                    outputBufferBits >>= 8;
                    outputBuffer[outputBufferEnd++] = unchecked((byte)outputBufferBits);
                    outputBufferBits >>= 8;
                    outputBuffer[outputBufferEnd++] = unchecked((byte)outputBufferBits);
                    outputBufferBits >>= 8;
                    outputBuffer[outputBufferEnd++] = unchecked((byte)outputBufferBits);
                    outputBufferBits >>= 8;
                    outputBuffer[outputBufferEnd++] = unchecked((byte)outputBufferBits);
                    outputBufferBits >>= 8;
                    outputBufferBitCount -= 48;


                    /*
                    outputBuffer[outputBufferEnd] = unchecked ((byte) outputBufferBits);
                    outputBuffer[outputBufferEnd+1] = unchecked ((byte) (outputBufferBits >> 8));
                    outputBuffer[outputBufferEnd+2] = unchecked((byte)(outputBufferBits >> 16));
                    outputBuffer[outputBufferEnd+3] = unchecked((byte)(outputBufferBits >> 24));
                    outputBuffer[outputBufferEnd+4] = unchecked((byte)(outputBufferBits >> 32));
                    outputBuffer[outputBufferEnd+5] = unchecked((byte)(outputBufferBits >> 40));
                    outputBufferEnd += 6;
                    outputBufferBits >>= 48;
                    outputBufferBitCount -= 48;
                    */
                }
            }
        }


        /// <summary>
        /// Writes Bits to to the output buffer
        /// </summary>
        /// <param name="bits">The bit values</param>
        /// <param name="count">The bit count</param>
        /// <remarks>RFC 1951 (3.1.1) defines the byte order as less significant bit first.
        /// </remarks>
        internal void OutputBufferWriteBits(ulong bits, int count) 
		{
            Debug.Assert(outputBufferStart == 0);
            outputBufferBits |= ((ulong)((uint) bits)) << outputBufferBitCount;
            outputBufferBitCount += count;

			if (outputBufferBitCount >= 48) 
            {
                if (outputBufferEnd + 6 >= outputBufferSize) SendBuffer();
                
                
                outputBuffer[outputBufferEnd++] = unchecked((byte)outputBufferBits);
                outputBufferBits >>= 8;
                outputBuffer[outputBufferEnd++] = unchecked((byte)outputBufferBits);
                outputBufferBits >>= 8;
                outputBuffer[outputBufferEnd++] = unchecked((byte)outputBufferBits);
                outputBufferBits >>= 8;
                outputBuffer[outputBufferEnd++] = unchecked((byte)outputBufferBits);
                outputBufferBits >>= 8;
                outputBuffer[outputBufferEnd++] = unchecked((byte)outputBufferBits);
                outputBufferBits >>= 8;
                outputBuffer[outputBufferEnd++] = unchecked((byte)outputBufferBits);
                outputBufferBits >>= 8;
                outputBufferBitCount -= 48;
                

                /*
                outputBuffer[outputBufferEnd] = unchecked ((byte) outputBufferBits);
                outputBuffer[outputBufferEnd+1] = unchecked ((byte) (outputBufferBits >> 8));
                outputBuffer[outputBufferEnd+2] = unchecked((byte)(outputBufferBits >> 16));
                outputBuffer[outputBufferEnd+3] = unchecked((byte)(outputBufferBits >> 24));
                outputBuffer[outputBufferEnd+4] = unchecked((byte)(outputBufferBits >> 32));
                outputBuffer[outputBufferEnd+5] = unchecked((byte)(outputBufferBits >> 40));
                outputBufferEnd += 6;
                outputBufferBits >>= 48;
                outputBufferBitCount -= 48;
                */
			}
		}

		/// <summary>
		/// Flushes the pending buffer into the given output array.  If the
		/// output array is to small, only a partial flush is done.
		/// </summary>
		/// <param name="output">The output array.</param>
		/// <param name="offset">The offset into output array.</param>
		/// <param name="length">The maximum number of bytes to store.</param>
		/// <returns>The number of bytes flushed.</returns>
        internal void OutputBufferFlush() 
		{
            SendBuffer();
		}


        private void SendBuffer(  )
        {
            StoreData(outputBuffer, outputBufferEnd, storeDataContext);
            outputBufferStart = 0;
            outputBufferEnd = 0;
        }

        byte[] outputBuffer;

        int outputBufferSize; // no need to check outputBuffer.Length

        int outputBufferStart;
        
        int outputBufferEnd;

        ulong outputBufferBits; // Stores Bits for bit operations - 

        int outputBufferBitCount;

        Deflater.StoreDataDelegate StoreData;
        object storeDataContext;

	}
}	
